package compute;

import java.util.ArrayList;
import java.util.Random;

import data.DataBloc;
import data.Key;

public class DesCfb extends Mode {

	/**
	 * constructeur par défaut
	 */
	public DesCfb() {
		blocEncrypter = new DES();
	}

	/**
	 * constructeur avec un clef spécifiée
	 * 
	 * @param k
	 */
	public DesCfb(Key k) {
		blocEncrypter = new DES(k);
	}

	@Override
	public byte[] encrypt(String plainText) {
		DataBloc Ci_1 = generateIV();

		ArrayList<DataBloc> plainTextData = DataBloc.toDataBloc(plainText);

		ArrayList<DataBloc> cypherTextData = new ArrayList<DataBloc>();

		cypherTextData.add(Ci_1);

		for (DataBloc Mi : plainTextData) {
			DataBloc encryptCi_1 = blocEncrypter.encrypt(Ci_1);
			byte[] Ci_1Bytes = encryptCi_1.getBytes();
			byte[] MiBytes = Mi.getBytes();
			byte[] xorResult = new byte[MiBytes.length];
			for (int i = 0; i < MiBytes.length; i++) {
				xorResult[i] = (byte) (Ci_1Bytes[i] ^ MiBytes[i]);
			}
			Ci_1 = DataBloc.toDataBlocs(xorResult).get(0);
			cypherTextData.add(Ci_1);
		}

		return DataBloc.toBytes(cypherTextData);
	}

	@Override
	public String decrypt(byte[] cypherText) {

		DataBloc Ci_1 = null;

		ArrayList<DataBloc> cypherTextData = DataBloc.toDataBlocs(cypherText);

		ArrayList<DataBloc> plainTextData = new ArrayList<DataBloc>();

		for (DataBloc Ci : cypherTextData) {
			if (Ci_1 != null) {
				DataBloc decryptCi_1 = blocEncrypter.encrypt(Ci_1);
				byte[] Ci_1Bytes = decryptCi_1.getBytes();
				byte[] CiBytes = Ci.getBytes();
				byte[] xorResult = new byte[CiBytes.length];
				for (int i = 0; i < CiBytes.length; i++) {
					xorResult[i] = (byte) (Ci_1Bytes[i] ^ CiBytes[i]);
				}
				plainTextData.add(DataBloc.toDataBlocs(xorResult).get(0));
			}
			Ci_1 = Ci;
		}

		return DataBloc.toString(plainTextData);
	}

	public Key getKey() {
		return ((DES) blocEncrypter).getKey();
	}

	public void setKey(Key k) {
		((DES) blocEncrypter).setKey(k);
	}

	/**
	 * génére le vecteur Initiale
	 * 
	 * @return
	 */
	public DataBloc generateIV() {
		byte b[] = new byte[8];
		Random r = new Random();
		r.nextBytes(b);
		ArrayList<DataBloc> data = DataBloc.toDataBlocs(b);
		return data.get(0);
	}

	public static void main(String[] args) {
		DesCfb desCfb = new DesCfb();
		String originalText = "Il était une fois dans l'ouest.";
		byte[] cypherText = desCfb.encrypt(originalText);
		String plainText = desCfb.decrypt(cypherText);
		System.out.println(originalText);
		System.out.println(cypherText.toString());
		System.out.println(plainText);
	}
}
